package org.xhy.hrm.service.impl;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.xhy.hrm.doc.CourseDoc;
import org.xhy.hrm.doc.query.CourseESQuery;
import org.xhy.hrm.mapping.HighlightResultMapper;
import org.xhy.hrm.repository.CourseElasticSearchRepository;
import org.xhy.hrm.service.ICourseESService;
import org.xhy.hrm.util.AjaxResult;
import org.xhy.hrm.util.PageList;
import org.xhy.hrm.vo.AggVo;
import org.xhy.hrm.vo.SearchPageList;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class CourseESServiceImpl implements ICourseESService {

    @Autowired
    private CourseElasticSearchRepository courseElasticSearchRepository;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public void save(CourseDoc courseDoc) {
        courseElasticSearchRepository.save(courseDoc);
    }

    @Override
    public void deleteById(Long id) {
        courseElasticSearchRepository.deleteById(id);
    }

    @Override
    public PageList search(CourseESQuery query) {
        // 记住！NativeSearchQueryBuilder  构建查询器
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        //指定索引库
        builder.withIndices("hrm");
        builder.withTypes("course");

        //分页
        builder.withPageable(PageRequest.of(query.getPage()-1, query.getRows()));

        //排序,前端发起的字段不匹配自己转换
        extracted(query, builder);

        //查询条件
        BoolQueryBuilder boolQueryBuilder = getQueryBuilder(query);

        builder.withQuery(boolQueryBuilder);

        //高亮
        HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'>").postTags("</font>");
        builder.withHighlightFields(field);

        //聚合
        getAgg(builder);

        //执行 courseElasticSearchRepository无法使用高亮，所以用原生的elasticsearchTemplate
        //Page<CourseDoc> courseDocPage = courseElasticSearchRepository.search(builder.build());
        AggregatedPage<CourseDoc> page = elasticsearchTemplate.queryForPage(builder.build(), CourseDoc.class, highlightResultMapper);

        //取出聚合
        Aggregations aggregations = page.getAggregations();
        //封装成map
        Map<String, List<AggVo>> aggMap = new HashMap<>();
        //遍历聚合 两个聚合
        aggregations.asList().forEach(aggregation -> {
            //装一个聚合结果
            List<AggVo> aggVoList = new ArrayList<>();
            ((StringTerms)aggregation).getBuckets().forEach(bucket -> {
                AggVo agg1 = new AggVo((String) bucket.getKey(), bucket.getDocCount());
                aggVoList.add(agg1);
            });
            aggMap.put(aggregation.getName(),aggVoList);

        });

        //getTotalElements()分页条数，getContent分页数据
        return new SearchPageList(page.getTotalElements(),page.getContent(),aggMap);
    }

    private void getAgg(NativeSearchQueryBuilder builder) {
        //等级聚合
        TermsAggregationBuilder gradeAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName").size(10);
        //租户聚合
        TermsAggregationBuilder tenantAgg = AggregationBuilders.terms("tenantNameAgg").field("tenantName").size(10);

        builder.addAggregation(gradeAgg).addAggregation(tenantAgg);
    }


    private void extracted(CourseESQuery query, NativeSearchQueryBuilder builder) {
        if(StringUtils.hasText(query.getSortField())){
            //转换字段
            String sortField = "saleCount";
            switch(query.getSortField()){
                case "xl": sortField = "saleCount"; break;
                case "xp": sortField = "onlineTime"; break;
                case "pl": sortField = "commentCount"; break;
                case "jg": sortField = "price"; break;
                case "rq": sortField = "viewCount"; break;
            }

            //转换排序方式   equalsIgnoreCase(比较忽略大小写)
            SortOrder sortOrder = SortOrder.DESC;
            if (StringUtils.hasText(query.getSortType()) && query.getSortType().equalsIgnoreCase("asc")){
                sortOrder = SortOrder.ASC;
            }

            builder.withSort(SortBuilders.fieldSort(sortField).order(sortOrder));
        }
    }


    private BoolQueryBuilder getQueryBuilder(CourseESQuery query) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //keyword
        if (StringUtils.hasText(query.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", query.getKeyword()));
        }
        //courseTypeId
        if (query.getCourseTypeId() != null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", query.getCourseTypeId()));
        }
        //gradeName
        if (StringUtils.hasText(query.getGradeName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", query.getGradeName()));
        }
        //tenantName
        if (StringUtils.hasText(query.getTenantName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("tenantName", query.getTenantName()));
        }
        //priceMax;
        if (query.getPriceMax() != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(query.getPriceMax()));
        }
        //priceMin;
        if (query.getPriceMin() != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(query.getPriceMin()));
        }
        return boolQueryBuilder;
    }
}
